﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Data;
using System.Net.Mail;

namespace DoeObjects
{
	public class User
	{
        public int UserId { get; set; }
        public UserCategory Category { get; set; }
        //public string UserName { get; set; }
        public string EMail { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Password { get; set; }
        public string Salt { get; set; }

        public string Room { get; set; }
        public string UniPhone { get; set; }
		public bool Activated { get; set; }
		public bool ExpireNotificationSent { get; set; }
		public DateTime RegistrationDate { get; set; }
		public DateTime? UserExpirationDate { get; set; }
        
        /// <summary>
        /// if the account is still not activated this field contains the user to accept the request
        /// </summary>
        public User Acceptor { get; set; }
		public bool IsPendingExpiration
		{
			get
			{
				if (UserExpirationDate.HasValue && UserExpirationDate.Value.Date <= DateTime.Now.Date && Activated)
					return true;
				else
					return false;
			}
		}

        public static bool activateUser(int userId)
        {
            int affectedRows = 0;
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("UPDATE [User] SET WaitingForActivation = NULL WHERE userId = @Id", connection);
            cmd.Parameters.AddWithValue("@Id", userId);

            try
            {
                connection.Open();
                affectedRows = cmd.ExecuteNonQuery();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return (affectedRows > 0);
        }

        public static string getUserMail(int userId)
        {
            
            string mail = "";
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("SELECT email FROM [User] WHERE userId = @Id", connection);
            cmd.Parameters.AddWithValue("@Id", userId);

            try
            {
                connection.Open();
                mail = cmd.ExecuteScalar().ToString();
            }
            catch (SqlException er)
            {
                throw er;
            }
            finally
            {
                 connection.Close();
            }
            return mail;
           
        }

        public static bool informDeneyedUser(string emailAddress) 
        {
            return MailManager.sendMail(emailAddress, "Your accountactivation", "<h3>Hi!</h3><p>Your account was denyed by your choosen accepter.</p> //Doelibs", MailPriority.High);
        }

        public static bool informActivatedUser(string emailAddress)
        {
            return MailManager.sendMail(emailAddress, "Your accountactivation", "<h3>Hi!</h3><p>Your account was activated by your choosen accepter.</p> //Doelibs");
        }

        internal static User getUserByUserId(int id, SqlConnection connection)
        {
            bool usedExistingConnection = true;
            if (connection == null)
            {
                connection = new SqlConnection(Settings.ConnectionString);
                usedExistingConnection = false;
            }

            SqlCommand command = new SqlCommand("SELECT * FROM [USER] INNER JOIN UserCategory ON [User].CategoryId = [UserCategory].UserCategoryId WHERE [USER].UserId = @UserId", connection);
            command.Parameters.AddWithValue("@UserId", id);

            User user = null;
            try
            {
                if (!usedExistingConnection)
                {
                    connection.Open();
                }

                SqlDataReader reader = command.ExecuteReader();
                if (reader.Read())
                {
                    user = getCurrentUser(reader);
                }
                reader.Close();
            }
            catch (SqlException ex)
            {
                //something bad happened.
                //TODO: log exception
            }
            finally
            {
                if (!usedExistingConnection && connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return user;
        }

        public static User getUserByUserId(int id)
        {
            return getUserByUserId(id, null);
        }

        /// <summary>
        /// creates a userobject from a datareader which contains userdata
        /// </summary>
        /// <param name="reader"></param>
        /// <returns></returns>
        internal static User getCurrentUser(SqlDataReader reader)
        {
            User user = null;

            if (reader != null)
            {
                user = new User();
                user.UserId = Convert.ToInt32(reader["UserId"]);
                //user.UserName = reader["userName"] as string;
                user.EMail = reader["email"] as string;
                user.FirstName = reader["firstName"] as string;
                user.LastName = reader["lastName"] as string;
                user.Password = reader["password"] as string;
                user.Salt = reader["salt"] as string;
                user.Category = UserCategory.getCurrentUserCategory(reader);
                user.Room = reader["room"] as string;
                user.UniPhone = reader["uniphone"] as string;
                user.Acceptor = (reader["WaitingForActivation"] == DBNull.Value) ? null : User.getUserByUserId((int)reader["WaitingForActivation"]);

				user.Activated = Convert.ToBoolean(reader["Activated"]);
				user.ExpireNotificationSent = Convert.ToBoolean(reader["ExpireNotificationSent"]);
				user.RegistrationDate = (DateTime)reader["RegistrationDate"];
				if (reader["UserExpirationDate"] == DBNull.Value) user.UserExpirationDate = null;
				else user.UserExpirationDate = (DateTime)reader["UserExpirationDate"];
            }

            return user;
        }

        //public static User getUserByUsername(string username)
        //{
        //    string sqlQuery = "SELECT * FROM [USER] INNER JOIN UserCategory ON [User].CategoryId = [UserCategory].UserCategoryId WHERE [USER].UserName=@Username";
        //    SqlParameter paramUsername = new SqlParameter("Username", SqlDbType.VarChar);
        //    paramUsername.Value = username;
        //    List<User> result = getUsersFromDatabase(sqlQuery, new List<SqlParameter> { paramUsername });
        //    if (result.Count != 0) return result[0];
        //    return null;
        //}

        public static User getUserByMail(string email)
        {
            string sqlQuery = "SELECT * FROM [USER] INNER JOIN UserCategory ON [User].CategoryId = [UserCategory].UserCategoryId WHERE [USER].Email=@email";
            SqlParameter paramMail = new SqlParameter("@email", SqlDbType.VarChar);
            paramMail.Value = email;
            List<User> result = getUsersFromDatabase(sqlQuery, new List<SqlParameter> { paramMail });
            if (result.Count != 0) return result[0];
            return null;
        }

		private static List<User> getUsersFromDatabase(string sqlQuery, List<SqlParameter> parameters)
		{
			List<User> result = new List<User>();
			SqlConnection connection = new SqlConnection(Settings.ConnectionString);
			SqlCommand command = new SqlCommand(sqlQuery, connection);

			foreach (SqlParameter p in parameters)
				command.Parameters.Add(p);

			try
			{
				connection.Open();
				SqlDataReader reader = command.ExecuteReader();

				while (reader.Read())
				{
                    result.Add(getCurrentUser(reader));
				}
			}
			catch (Exception e)
			{
				throw e;
				// Some way to print to user?
			}
			finally
			{
				connection.Close();
			}
			return result;
		}

        public static List<User> getUsersOfCategory(UserCategory cat)
        {
            return getUsersOfCategory(cat.CategoryId);
        }

        public static List<User> getUsersOfCategory(string name)
        {
            UserCategory cat = UserCategory.getByName(name);
            if (cat != null)
            {
                return getUsersOfCategory(cat.CategoryId);
            }
            else
            {
                return new List<User>();
            }
        }

        public static List<User> getUsersOfCategory(int catId)
        {
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand command = new SqlCommand("SELECT * FROM [User] INNER JOIN UserCategory ON [User].CategoryId = [UserCategory].UserCategoryId WHERE CategoryId = @id", connection);
            command.Parameters.AddWithValue("@id", catId);

            List<User> result = new List<User>();
            try
            {
                connection.Open();

                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                {
                    result.Add(getCurrentUser(reader));
                }
                reader.Close();
            }
            catch (SqlException ex)
            {
                //something bad happened.
                //TODO: log exception
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }
            return result;
        }

        public static int add(User user)
        {
            int lastInsertedId = 0;
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("INSERT INTO [User] (Email, FirstName, LastName, Password, Salt, CategoryId, WaitingForActivation, " +
				"Room, UniPhone, Activated, RegistrationDate, UserExpirationDate, ExpireNotificationSent) OUTPUT INSERTED.UserId VALUES " +
				"(@EMail, @FirstName, @LastName, @Password, @Salt, @CategoryId, @Acceptor, @Room, @UniPhone, @Activated, @RegistrationDate, @UserExpirationDate, " +
				"@ExpireNotificationSent)", connection);
            
            //SqlParameter nameParam = new SqlParameter("@UserName", SqlDbType.NVarChar);
            //nameParam.Value = user.UserName;
            SqlParameter mailParam = new SqlParameter("@EMail", SqlDbType.NVarChar);
            mailParam.Value = user.EMail;
            SqlParameter fnParam = new SqlParameter("@FirstName", SqlDbType.NVarChar);
            fnParam.Value = user.FirstName;
            SqlParameter lnParam = new SqlParameter("@LastName", SqlDbType.NVarChar);
            lnParam.Value = user.LastName;
            SqlParameter passParam = new SqlParameter("@Password", SqlDbType.NVarChar);
            passParam.Value = user.Password;
            SqlParameter saltParam = new SqlParameter("@Salt", SqlDbType.NVarChar);
            saltParam.Value = user.Salt;
            SqlParameter roomParam = new SqlParameter("@Room", SqlDbType.NVarChar);
            roomParam.Value = (string.IsNullOrEmpty(user.Room))?DBNull.Value:(Object)user.Room;
            SqlParameter phoneParam = new SqlParameter("@UniPhone", SqlDbType.NVarChar);
            phoneParam.Value = (string.IsNullOrEmpty(user.UniPhone)) ? DBNull.Value : (Object)user.UniPhone;
			SqlParameter expireNotParam = new SqlParameter("@ExpireNotificationSent", SqlDbType.Bit) { Value = 0 };

			DateTime currentDate = DateTime.Now.Date;
			SqlParameter activatedParam = new SqlParameter("@Activated", SqlDbType.Bit) { Value = 1 };
			user.Activated = true;
			SqlParameter registrationDateParam = new SqlParameter("@RegistrationDate", SqlDbType.DateTime) { Value = currentDate };
			user.RegistrationDate = currentDate;
			SqlParameter userExpirationDateParam = new SqlParameter("@UserExpirationDate", SqlDbType.DateTime);
			if (user.Category.CategoryId == 1) userExpirationDateParam.Value = DBNull.Value;//userExpirationDateParam.Value = currentDate.AddYears((Settings.StaffExpireTimeInYears == 0) ? 6 : Settings.StaffExpireTimeInYears);
			else
			{
				userExpirationDateParam.Value = currentDate.Add(Settings.StudentExpireTime);
				user.UserExpirationDate = currentDate.Add(Settings.StudentExpireTime);
			}

            cmd.Parameters.AddWithValue("@CategoryId", user.Category.CategoryId);
            cmd.Parameters.Add(mailParam);
            cmd.Parameters.Add(fnParam);
            cmd.Parameters.Add(lnParam);
            cmd.Parameters.Add(passParam);
            cmd.Parameters.Add(saltParam);
            cmd.Parameters.Add(roomParam);
            cmd.Parameters.Add(phoneParam);
            cmd.Parameters.AddWithValue("@Acceptor", (user.Acceptor == null) ? DBNull.Value : (Object)user.Acceptor.UserId);
			cmd.Parameters.Add(activatedParam);
			cmd.Parameters.Add(registrationDateParam);
			cmd.Parameters.Add(userExpirationDateParam);
			cmd.Parameters.Add(expireNotParam);

            try
            {
                connection.Open();
                Object res = cmd.ExecuteScalar();
                if (res != null)
                {
                    lastInsertedId = (int)res;
                }
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return lastInsertedId;
        }

        public static bool update(User user)
        {
            int affectedRows = 0;
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("UPDATE [User] SET Email = @EMail, FirstName = @FirstName, LastName = @LastName, Password = @Password, Salt = @Salt, " +
				"CategoryId = @CategoryId, WaitingForActivation = @Acceptor, Room = @Room, UniPhone = @UniPhone, " +
				"Activated=@Activated, RegistrationDate=@RegistrationDate, UserExpirationDate=@UserExpirationDate, " +
				"ExpireNotificationSent=@ExpireNotificationSent WHERE userId = @Id", connection);
            
            //SqlParameter nameParam = new SqlParameter("@UserName", SqlDbType.NVarChar);
            //nameParam.Value = user.UserName;
            SqlParameter mailParam = new SqlParameter("@EMail", SqlDbType.NVarChar);
            mailParam.Value = user.EMail;
            SqlParameter fnParam = new SqlParameter("@FirstName", SqlDbType.NVarChar);
            fnParam.Value = user.FirstName;
            SqlParameter lnParam = new SqlParameter("@LastName", SqlDbType.NVarChar);
            lnParam.Value = user.LastName;
            SqlParameter passParam = new SqlParameter("@Password", SqlDbType.NVarChar);
            passParam.Value = user.Password;
            SqlParameter saltParam = new SqlParameter("@Salt", SqlDbType.NVarChar);
            saltParam.Value = user.Salt;
            SqlParameter roomParam = new SqlParameter("@Room", SqlDbType.NVarChar);
            roomParam.Value = (string.IsNullOrEmpty(user.Room)) ? DBNull.Value : (Object)user.Room;
            SqlParameter phoneParam = new SqlParameter("@UniPhone", SqlDbType.NVarChar);
            phoneParam.Value = (string.IsNullOrEmpty(user.UniPhone)) ? DBNull.Value : (Object)user.UniPhone;

			SqlParameter activatedParam = new SqlParameter("@Activated", SqlDbType.Bit) { Value = user.Activated };
			SqlParameter registrationDateParam = new SqlParameter("@RegistrationDate", SqlDbType.DateTime) { Value = user.RegistrationDate };
			SqlParameter userExpirationDateParam = new SqlParameter("@UserExpirationDate", SqlDbType.DateTime);
			if (user.UserExpirationDate == null) userExpirationDateParam.Value = DBNull.Value;
			else userExpirationDateParam.Value = user.UserExpirationDate;
			SqlParameter expireNot = new SqlParameter("@ExpireNotificationSent", SqlDbType.Bit) { Value = user.ExpireNotificationSent };


            cmd.Parameters.AddWithValue("@Id", user.UserId);
            cmd.Parameters.AddWithValue("@CategoryId", user.Category.CategoryId);
            cmd.Parameters.Add(mailParam);
            cmd.Parameters.Add(fnParam);
            cmd.Parameters.Add(lnParam);
            cmd.Parameters.Add(passParam);
            cmd.Parameters.Add(saltParam);
            cmd.Parameters.Add(roomParam);
            cmd.Parameters.Add(phoneParam);
            cmd.Parameters.AddWithValue("@Acceptor", (user.Acceptor == null) ? DBNull.Value : (Object)user.Acceptor.UserId);
			cmd.Parameters.Add(activatedParam);
			cmd.Parameters.Add(registrationDateParam);
			cmd.Parameters.Add(userExpirationDateParam);
			cmd.Parameters.Add(expireNot);

            try
            {
                connection.Open();
                affectedRows = cmd.ExecuteNonQuery();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return (affectedRows > 0);
        }

        public bool save()
        {
            if (this.UserId == 0)
            {
                this.UserId = User.add(this);
                return (this.UserId > 0);
            }
            else
            {
                return User.update(this);
            }
        }

        public static bool delete(int userId)
        {
            int affectedRows = 0;
            SqlConnection connection = new SqlConnection(Settings.ConnectionString);
            SqlCommand cmd = new SqlCommand("DELETE FROM [User] WHERE UserId = @Id", connection);

            cmd.Parameters.AddWithValue("@Id", userId);
            
            try
            {
                connection.Open();
                affectedRows = cmd.ExecuteNonQuery();
            }
            catch (SqlException er)
            {
                //oo
                throw er;
            }
            finally
            {
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }

            return (affectedRows > 0);
        }

		public static List<User> getUsersAboutToExpireWhereNotificationNotSent()
		{
			SqlConnection connection = new SqlConnection(Settings.ConnectionString);
			SqlCommand command = new SqlCommand("SELECT * FROM [USER] INNER JOIN UserCategory ON " +
				"[User].CategoryId = [UserCategory].UserCategoryId WHERE [USER].UserExpirationDate IS NOT NULL AND " +
				"[USER].UserExpirationDate<=DATEADD(month, 1, GETDATE()) " +
				"AND [User].Activated=1 AND [User].ExpireNotificationSent=0", connection);
			List<User> result = new List<User>();

			try
			{
				connection.Open();

				SqlDataReader reader = command.ExecuteReader();
				while (reader.Read())
					result.Add(getCurrentUser(reader));
				reader.Close();
			}
			catch (SqlException ex)
			{ }
			finally
			{
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
			return result;
		}

		public static List<User> getExpiredUsers()
		{
            string sqlCmd = @"
SELECT * FROM [USER] 
INNER JOIN UserCategory 
ON [User].CategoryId = [UserCategory].UserCategoryId 
WHERE [USER].UserExpirationDate IS NOT NULL 
AND [USER].UserExpirationDate <= GETDATE() AND [User].Activated = 1";

			SqlConnection connection = new SqlConnection(Settings.ConnectionString);
			SqlCommand command = new SqlCommand(sqlCmd, connection);
			List<User> result = new List<User>();

			try
			{
				connection.Open();

				SqlDataReader reader = command.ExecuteReader();
				while (reader.Read())
					result.Add(getCurrentUser(reader));
				reader.Close();
			}
			catch (SqlException ex)
			{
                
            }
			finally
			{
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
			return result;
		}

		public static void handleExpiredUsers()
		{
			List<User> notificationNeeded = getUsersAboutToExpireWhereNotificationNotSent();
			foreach (User user in notificationNeeded)
			{
				Notification not = new Notification();
				not.Recipient = user;
				not.Message = string.Format("Your account is expiring at {0}.", user.UserExpirationDate.Value.Date);
				not.Type = NotificationType.UNKNOWN;
				not.save();

				user.ExpireNotificationSent = true;
				bool test = user.save();
			}

			List<User> expiredUsers = getExpiredUsers();
			foreach (User user in expiredUsers)
			{
				bool borrowedLoanablesLeft = false;
				if (user.Category.CategoryId == 1)
				{
					if (Loanable.getBorrowedLoanablesByOwner(user.UserId).Count != 0)
						borrowedLoanablesLeft = true;

					List<Loanable> ownerLoanables = Loanable.getLoanablesByOwner(user.UserId);
					foreach (Loanable loanable in ownerLoanables)
					{
						if (loanable.Status == Status.UNAVAILABLE_FROM_OWNER)
							Loanable.delete(loanable);
					}
				}

				List<Loan> activeLoans = Loan.getActiveLoansFromUser(user.UserId);
				if (activeLoans.Count == 0)
				{
					if (!borrowedLoanablesLeft)
					{
						Reservation.deleteUserReservations(user.UserId);
						user.Activated = false;
						if (user.save()) MailManager.sendMail(user.EMail, "DoeLibS Account", "<h3>Hi!</h3><p>Your DoeLibS account has expired.</p> //Doelibs");
					}
				}
				else
				{
					foreach (Loan loan in activeLoans)
						if (loan.ReasonForRecall != RecallReason.USER_EXPIRE) loan.recall(RecallReason.USER_EXPIRE);

					Reservation.deleteUserReservations(user.UserId);
				}
			}
		}

		public bool expireUser(List<int> transferLoanablesIds, int toUserId)
		{
			if (this.IsPendingExpiration) return false;

			User newOwner = User.getUserByUserId(toUserId);
			if (newOwner == null || newOwner.Category.CategoryId != 1)
				return false;

			this.ExpireNotificationSent = true;
			this.UserExpirationDate = DateTime.Now.Date;
			if (!this.save()) return false;
			if (this.Category.CategoryId == 1) MailManager.sendMail(this.EMail, "DoeLibS Account", "<h3>Hi!</h3><p>Your DoeLibS account has been set to be removed. All your borrowings has been recalled and all loans placed on any of your loanables has been recalled. When all loanables is returned you will no longer be able to log into the system.</p> //Doelibs");
			else MailManager.sendMail(this.EMail, "DoeLibS Account", "<h3>Hi!</h3><p>Your DoeLibS account has been set to be removed. All your borrowings has been recalled and when all loanables is returned you will no longer be able to log into the system.</p> //Doelibs");

			Notification not = new Notification();
			not.Recipient = this;
			not.Message = "Your account has been set to be removed.";
			not.Type = NotificationType.UNKNOWN;
			not.save();

			Loanable.transferLoanablesToUser(transferLoanablesIds, this.UserId, toUserId);

			List<Loanable> loanables = Loanable.getLoanablesByOwner(this.UserId);
			foreach (Loanable loanable in loanables)
				Loanable.OwnerRecall(loanable.LoanableId);

			handleExpiredUsers();
			return true;
		}

		public void renewExpirationDate()
		{
			if (Category.CategoryId == 2)
			{
				if (UserExpirationDate.HasValue)
					UserExpirationDate = UserExpirationDate.Value.Date.Add(Settings.StudentExpireTime);
				else
					UserExpirationDate = DateTime.Now.Date.Add(Settings.StudentExpireTime);
				ExpireNotificationSent = false;
				save();
			}
			else if (Category.CategoryId == 1)
			{
				ExpireNotificationSent = false;
				UserExpirationDate = null;
				save();
			}
		}

		public static List<User> getUsersBySearchPhrase(string search, int? categoryId = null)
		{
			if (String.IsNullOrEmpty(search)) return new List<User>();
			SqlConnection connection = new SqlConnection(Settings.ConnectionString);
			SqlCommand command;
			if (!categoryId.HasValue)
			{
				command = new SqlCommand("SELECT * FROM [USER] INNER JOIN UserCategory ON " +
					"[User].CategoryId = [UserCategory].UserCategoryId WHERE [User].Activated=1 AND (LOWER([User].FirstName+' '+[User].LastName) LIKE @Search OR [User].Email LIKE @Search)", connection);
			}
			else
			{
				command = new SqlCommand("SELECT * FROM [USER] INNER JOIN UserCategory ON " +
					"[User].CategoryId = [UserCategory].UserCategoryId WHERE [User].Activated=1 AND [User].CategoryId=@CategoryId AND(LOWER([User].FirstName+' '+[User].LastName) LIKE @Search OR [User].Email LIKE @Search)", connection);
				SqlParameter categoryIdParam = new SqlParameter("@CategoryId", SqlDbType.Int) { Value = categoryId.Value };
				command.Parameters.Add(categoryIdParam);
			}
			SqlParameter searchParam = new SqlParameter("@Search", SqlDbType.VarChar) { Value = "%" + search + "%" };
			command.Parameters.Add(searchParam);

			List<User> result = new List<User>();

			try
			{
				connection.Open();

				SqlDataReader reader = command.ExecuteReader();
				while (reader.Read())
					result.Add(getCurrentUser(reader));
				reader.Close();
			}
			catch (SqlException ex)
			{ }
			finally
			{
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}
			return result;
		}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reason"> String telling user why there book was recalled. I.E. owner wants it back or someone reserved it</param>
        public void recallAllLoans(RecallReason reason)
        {
            foreach(Loan loan in Loan.getLoansFromUser(this.UserId))
                loan.recall(reason);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="reason"> String telling user why there book was recalled. I.E. owner wants it back or someone reserved it</param>
        /// <param name="RecalledDate">Force the recalled date to be somehting other than today</param>
        public void recallAllLoans(RecallReason reason, DateTime RecalledDate)
		{
			foreach (Loan loan in Loan.getLoansFromUser(this.UserId))
				loan.recall(reason, RecalledDate);
        }
	}
}
